/*
 * Copyright (c) 2010, David Foley
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without 
 * modification, are permitted provided that the following conditions are met:
 *
 *     Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 * 
 *     Redistributions in binary form must reproduce the above copyright notice, 
 *     this list of conditions and the following disclaimer in the documentation 
 *     and/or other materials provided with the distribution.
 * 
 *     Neither the name of David Foley, OnDevice.ie nor the names of its 
 *     contributors may be used to endorse or promote products derived from this 
 *     software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 * POSSIBILITY OF SUCH DAMAGE.
 */

/**
 * @fileoverview An overview TODO
 */
new function ()
{
        /**
         * @private
         * A reference to the Function protoype
         * @type Object
         */
    var F= Function.prototype
        /**
         * @private
         * A reference to the Array slice method
         * @type Function
         */
    ,   S= Array.prototype.slice
    
        /**
         * @private
         * The anonymous keyword
         * @type String
         */
    ,   A= 'anonymous';
    
    /**
     * Add members to a functions prototype. This method can be called on
     * any function, but is designed for use with functions to be used as 
     * constructors. Given a custom constructor of your own making, you can
     * define your object classes in a very readable way.
     * 
     * <code><pre>
     *     
     *     // Use the implement method on a constructor to define a property
     *     // called 'property', an accessor method named 'getProperty' and
     *     // a mutator method named 'setProperty' by passing it an object literal
     *     // with properties (referred to as a traits provider)
     *     Abstract.implement
     *     (
     *         {
     *             property: null
     *         ,   getProperty: function () 
     *             {
     *                 return this.property;
     *             }
     *             
     *         ,   setProperty: function (value) {
     *             {
     *                 this.property= value;
     *             }
     *         }
     *     );
     *     
     *     // hoisting in JavaScript means you can define your constructor
     *     // after implementing your class properties to improve readability
     *     
     *     function Abstract (value) 
     *     {
     *         this.setProperty(value);
     *     };
     *     
     *     // You can call implement on any constructor at any time. In addition
     *     // to providing a traits provider to the implements method, you can 
     *     // also provide any number of named functions. These functions will
     *     // be added to the prototype by name. The end result is that your
     *     // class definitions become a lot less noisy and easier to read
     *     
     *     Abstract.implement
     *     (
     *         function compare (value) 
     *         {
     *             if (false === value instanceof Abstract)
     *                 return false;
     *             
     *             return this.property === value.getProperty();
     *         }
     *     );
     *     
     *     // you can also supply the prototype of other constructors to
     *     // the implement method on another, and all of its members will be 
     *     // copied over. This is NOT inheritance, but a way of using the
     *     // properties as other objects as 'traits providers'. In the example
     *     // below, AnotherClass.prototype now as all the properties of
     *     // Abstract.prototype
     *     
     *     AnotherClass.implement(Abstract.prototype);
     *     function AnotherClass (value)
     *     {
     *         Abstract.call(this, value);
     *     };
     *     
     *     var value= 'someValue'
     *     ,   abstract= new Abstract(value)
     *     ,   another= new AnotherClass(value)
     *     ,   hasAllAbstractsProperties= true
     *     ,   isAbstract= false
     *     
     *     for (var accessor in Abstract.prototype)
     *     {
     *         if (accessor in another) // always true in this case
     *             continue;
     *             
     *         hasAllAbstractsProperties= false;
     *     }
     *     
     *     // hasAllAbstractsProperties remains true
     *     
     *     isAbstract= another instanceof Abstract // false
     * 
     * </pre></code>
     * <p>
     * Note that Anonymous functions supplied outside of traits providers are 
     * not added to consructor prototypes (as there's nothing to call them), and
     * neither are null values. For best results, use object literals or
     * constructor prototypes as traits providers, and named functions to define
     * methods. The implement method will accept all other values, so try not to 
     * inadvertantly supply strings, numbers and arrays.
     * </p>
     * 
     * @param {...Object} rest    Any number of arguments of any type.
     * @return {Function}         A reference to the constructor that the method 
     *                            was called on.
     * 
     * @see Function#implementStatic
     * @see Function#implement.preventOverride
     * @memberOf Function
     * @addon
     */
    F.implement= function () 
    {
        this.implementStatic.apply(this.prototype, arguments);
        return this;  
    };

    /**
     * A flag variable that can be used to determine whether #implementStatic
     * or #implement will prevent the overwriting of members. By default this
     * value is true, meaning that if a trait is supplied to the implement
     * or implementStatic method that has the name of an existing property,
     * it will be skipped.
     * 
     * Flag this variable as false to allow overriding, and note that
     * after each invocation of an implementation method, that its value is
     * reset to true.
     * 
     * <code><pre>
     * 
     *     Array.implement
     *     (
     *         // this method wont be added to the Array prototype, as by default
     *         // preventOverride is true, and the push method is already defined
     *         function push () 
     *         {
     *             throw new Error ('FUBAR');
     *         }
     *     );
     *     
     *     // turn off protection
     *     Function.prototype.implement.preventOverride= false;
     * 
     *     Array.implement
     *     (
     *         // you're in trouble now! This method will override the native
     *         // push method
     *         function push () 
     *         {
     *             throw new Error ('FUBAR');
     *         }
     *     );
     *     
     *     // no need to turn on protection again, that happens automatically
     *     
     *     Array.implement
     *     (
     *         // preventOverride has been reset to false, so this method
     *         // will not be added
     *         function sort ()
     *         {
     *             throw new Error ('FUBARx2');
     *         }
     *     };
     * 
     * </pre></code>
     * 
     * @type {Boolean}
     * 
     * @see Function#implementStatic
     * @see Function#implement
     * @memberOf Function
     * @addon
     */
    F.implement.preventOverride= true;

    /**
     * Add 'static' members to a function. The same rules apply to this method 
     * as the implement method. The difference is that while the
     * implement method adds traits to a constructors prototype, this method
     * adds traits directly to the constructor.
     * 
     * <code><pre>
     *     
     *     // this is not an endorsement- for example only
     *     Singleton.defineStatic
     *     (
     *         {
     *             // a 'static' property
     *             instance: null
     *         }
     *         
     *         // a 'static' method
     *     ,   function getInstance ()
     *         {
     *             if (this.instance instanceof this)
     *                 return this.instance;
     *                 
     *             return this.instance= new this;
     *         }
     *     );
     *     
     *     function Singleton ()
     *     {
     *         if (this.constructor.instance)
     *             throw new Error ('Singleton already instantiated');
     *     };
     *     
     *     var instance= Singleton.getInstance()
     *     ,   reference= Singleton.getInstance()
     *     
     *     alert(instance === reference); // true
     *     
     *     new Singleton; // throws error
     * </pre></code>
     * 
     * @param {...Object} rest   Any number of objects or named functions.
     * @return {Function}        A reference to the constructor that this method
     *                           was used on.
     * 
     * @see Function#implement
     * @see Function#implement.preventOverride
     * @memberOf Function
     * @addon
     */
    F.implementStatic= function () 
    {
        var trait= null
        ,   n= arguments.length
        ,   i= 0
        ,   canOverwrite= !F.implement.preventOverride
        ,   accessor
        
        for (; i < n; i++) 
        {
            trait= arguments[i];
            if (null == trait)
                continue;

            if ('function' === typeof trait) 
            {
                accessor= trait.getName(); 
                if (A !== accessor && (canOverwrite || !(accessor in this)))
                    this[accessor]= trait;
            }
            else for (accessor in trait) 
            {
                if (canOverwrite || !(accessor in this))
                    this[accessor]= trait[accessor];
            }
        }
        
        F.implement.preventOverride= true;
        return this;
    };

    /**
     * Determine a functions name. If the function is anonymous, the string
     * 'anonymous' will be returned. This method is especially usefull for
     * reflection.
     * 
     * <code><pre>
     * 
     *     // this is not an endorsement! for example only
     *     Object.defineStatic
     *     (
     *         function nameFor (value) 
     *         {
     *             if (null == value)
     *                 return String(value);
     *                 
     *             if (value instanceof Function)
     *                 return value.getName();
     *                 
     *             return '[object ' + Object(value).constructor.getName() + ']';
     *         }
     *     );
     *     
     *     function MyClass () {;};
     *     
     *     var instance= new MyClass;
     *     
     *     alert(Object.nameFor(instance)); // alerts '[object MyClass]';
     *     
     * 
     * </pre></code>
     * 
     * @return {String}    The name of a function.
     * @memberOf Function
     * @addon
     */
    F.getName= ('name' in F) 
    ?
    function () 
    {
        var name= this.name;
        if ('' === name || 'Empty' === name)
            return A;
            
        return name;
    }
    :
    function () 
    {
	    var result = String(this).match(/^function\s([\w|$]+)/);
	    return String(result ? result[1] : A);
    };
    
    // N.B from this point on we could have used Function.implement but google
    // closure compiler does not retain function names passed as arguments. For
    // your own code produced with these extensions, and assuming you want
    // compression in addition to whitespace removal, do not use named functions
    // and instead supply an object literal to the implement or implementStatic
    // methods.
    
    /*
     * Extend one functions prototype by another, using a constructor as
     * the sole parameter. The inheriting prototype will have an additional
     * property called 'parent' added to it, which will refer to the
     * supertypes prototype.
     * 
     * <code><pre>
     * 
     *     // Our base class
     *     Person.define
     *     (
     *         {
     *             value: null
     *         }
     *     
     *     ,   function setAge (value)
     *         {
     *             this.value= value;
     *         }
     *         
     *     ,   function getAge ()
     *         {
     *             return this.value;
     *         }
     *     };
     *     
     *     function Person (age)
     *     {
     *         this.setAge(age);
     *     };
     *     
     *     // allow override of the setAge method
     *     Function.prototype.implement.preventOverride= false;
     *     
     *     // inherit from person
     *     Employee.inherits(Person);
     *     Employee.define
     *     (
     *         // override
     *         function setAge (value)
     *         {
     *             // implement a custom gaurd clause
     *             if (value < 16)
     *                 throw new Error('Too young to work here!');
     *             // invoke the supertypes setAge method to
     *             // actually set the age
     *             this.parent.setAge.call(this, value);
     *         }
     *     );
     *     
     *     function Employee (age)
     *     {
     *         // initialize the employee by invoking the supertype
     *         // constructor in the scope of this instance
     *         Person.call(this, age); 
     *     };
     *     
     *     var employee= new Employee (23);
     *     
     *     alert(employee instanceof Person); // true
     *     
     *     // alternatively, you can use the type method
     *     
     *     alert(Person.type(employee)); // true
     * 
     * </pre></code>
     * 
     * <p>
     * This method is also usefull in cases where you want to construct objects
     * indirectly.
     * </p>
     * 
     * <code><pre>
     * 
     *     Factory=
     *     {
     *         newInstance: function (Constructor)
     *         {
     *             if (false === Function.type(Constructor))
     *                 throw new Error('Function expected');
     *             
     *             // grab any additional arguments supplid to the newInstnace function
     *             var suppliedArgs= [].slice.call(arguments, 1);
     *             
     *             // subclass the constructor
     *             Proxy.inherits(Constructor);
     *             // parameterise the supertype constructor with the arguments
     *             function Proxy () 
     *             {
     *                 Constructor.apply(this, suppliedArgs);
     *             };
     *             
     *             // and you're done
     *             return new Proxy;
     *         }
     *     };
     *     
     *     Mixin.implementStatic
     *     ({
     *         HIGH_PRIORITY: 1
     *     ,   LOW_PRIORITY: 0
     *     })
     *     Mixin.implement
     *     (
     *         {
     *             priority: null
     *         ,   id: null
     *         }
     *         
     *     ,   function isHighPriority ()
     *         {
     *             return Mixin.HIGH_PRIORITY === this.priority;
     *         }
     *         
     *     ,   function hasId (value)
     *         {
     *             return this.id === value;
     *         }
     *     );
     *     
     *     function Mixin (id, importantCondition)
     *     {
     *         this.id= id;
     *         
     *         this.priority= importantCondition ? Mixin.HIGH_PRIORITY : Mixin.LOW_PRIORITY;
     *     };
     *     
     *     var mixin= Factory.newInstance(Mixin, 12345, true);
     *     ,   isHighPriority= mixin.isHighPriority(); // true
     *     ,   hasId= mixin.hasId(12345); // true
     *     ,   isMixinType= Mixin.type(mixin); // true
     *     
     * </pre></code>
     * 
     * @param {Function} Super    The constructor to inherit from.
     * @return {Function}         A reference to the function the operation was 
     *                            applied to, or null, if inheritence could not
     *                            be accomplished.
     * @memberOf Function
     * @addon
     */
    
    /**
     * Extend a constructors prototype by another. This method emulates classical
     * inheritance.
     * 
     * <code>
     *     <pre>
     *     
     *         Person.implement
     *         (
     *             {
     *                 age: null
     *             }
     *         );
     *         
     *         function Person (age)
     *         {
     *         
     *         };
     *     
     *     </pre>
     * </code>
     * 
     * @param {Function} Super    The constructor to inherit from
     * @return {Function}         The constructor that inherited from Super
     */
    F.inherits= function (Super) 
    {
       if (this === Super || 'function' !== typeof Super)
            return;
          
        function Intermediary () {;};
        Intermediary.prototype= Super.prototype;
        Intermediary.prototype.parent= Super.prototype;
        Intermediary.prototype.constructor= this;

        this.prototype= new Intermediary;

        return this;
    };
    
    /**
     * Bind or curry a function by supplying an object scope followed by 
     * any number of arguments. If null or undefined is supplied for the
     * scope argument, the function will execute in the global scope.
     * 
     * @param {Object} scope      The object scope to execute the method in.
     * @param {...Object} rest    Any number of arguments.
     * @return {Function}         A curried function.
     * @memberOf Function
     * @addon
     */
    F.bind= function (scope) 
    {
        var method= this
        ,   presetArgs= S.call(arguments, 1)

        if (presetArgs.length) return function () 
        {
            return method.apply(scope, presetArgs.concat(arguments));
        }
        else return function () 
        {
             return method.apply(scope, arguments);
        }
    };
    
    /**
     * Determine if an object was constructed by this function or one
     * of its subclasses. As a convenience, this method elides the distinction
     * between primitive values and their object counterparts. This rule
     * applies to string, number and boolean only. 
     * 
     * <code><pre>
     *     
     *     var primitive= 'string';
     *     alert(primitive instanceof Object); // false
     *     alert(primtiive instanceof String); // false!
     *     
     *     // this means checking for strings can be a paaaaiiin
     *     
     *     isString= 'string' === typeof value || value instanceof String
     *     
     *     // this way, its much easier, and the method is available on
     *     // every constructor, including your own.
     *     
     *     alert(String.type(primitive)); // true!
     *     alert(Number.type(0)); // true!
     *     alert(Boolean.type(false)); // true!
     * 
     *     // and of course, it works for your own objects as well
     *     
     *     function WhizzbangSuperDuperClass ()
     *     {
     *         ;
     *     };
     *     
     *     var instance= new WhizzbangSuperDuperClass;
     *     
     *     alert(WhizzbangSuperDuperClass.type(instance)); // true
     * 
     * 
     * </pre></code>
     * 
     * @param {Object} value    Any value.
     * @return {Boolean}        Whether or not a value is considered a type.
     * @see Function#is
     * @memberOf Function
     * @addon
     */
    F.type= function (value) 
    {  
        return null == value ? false : Object(value) instanceof this;
    };
        
    /**
     * Determine if an object was constructed by a particular constructor, and 
     * only that constructor.
     * 
     * <code><pre>
     * 
     *     function Superconstuctor () {};
     *     
     *     Constructor.inherits(Superconstructor);
     *     function Constructor () {};
     *     
     *     alert(Object.is(new Constructor)); // false- not constructed by Object
     *     alert(Object.type(new Constructor)); // true- inherits from Object
     *     alert(Constructor.type(new Constructor)); true- constructed by Constructor
     *     alert(Superconstructor.is(new Constructor)); // false- not constructed by Superconstructor
     *     alert(Superconstructor.type(new Constructor)); // true
     *     
     * 
     * </pre></code>
     * 
     * @param {Object} value    Any value.
     * @return {Boolean}        Whether or not
     * @see Function#type
     * @memberOf Function
     * @addon
     */
    F.is= function (value) 
    {
        return null == value ? false : value.constructor === this;
    };
    
    /**
     * Defer a function for execution at a later time. The returned object
     * provides the means to further control the execution of the method and
     * has the following properties:
     * 
     * <code>
     *     hasExecuted:Boolean    whether or not the function has executed
     * </code>
     * <code>    
     *     createdOn:Number       the UTC time at which the deferred function 
     *                            was created.
     * </code>
     * <code>
     *     interval:Number        the number of milliseconds until the deferred
     *                            function will be executed
     * </code>
     * <code>
     *     result:Object          the result of the deferred functions execution, 
     *                            assuming it returns a value. This property is
     *                            set after the deferred function has been
     *                            executed.
     * </code>
     * <code>
     *     fault:Error            an error object if there was a problem 
     *                            executing the function. This property is
     *                            set after the deferred function has been
     *                            executed.
     * </code>
     * <p>
     * The returned object has the following methods:
     * </p>
     * <code>
     *     execute                Executes the function, then disposes of it
     *                            to aid garbage collection. This method can
     *                            be invoked at any time, lest you need to
     *                            execute the deferred method before the 
     *                            interval expires. Note that after invoking
     *                            this method, the deferred function cannot
     *                            be executed again.
     * </code>
     * <code>                           
     *     dispose                Dispose of the function. The deferred 
     *                            method will be cancelled and not invoked
     *                            again.
     * </code>
     * <p>
     * You can also define a callback by adding a function called 'onExecute'
     * to the returned object. The callback will be parameterised with a
     * boolean value of true or false pending on whether the deferred function
     * executed normally or encountered a fault while executing.
     * </p>
     * <code><pre>
     * 
     *     function sayHi ()
     *     {
     *         sayIt('hi');
     *     };
     *     
     *     function sayIt (message)
     *     {
     *         alert(message);
     *     };
     *     
     *     // defer execution for 100 milliseconds
     *     var deferred= sayHi.defer(100);
     *     // add a callback
     *     deferred.onExecute= function (status)
     *     {
     *         if (status)
     *             alert('executed ok');
     *         else
     *             alert('dammit');
     *     };
     *     
     *     // if you left the above alone, the sayHi method would be executed
     *     // in 100 milliseconds time (or thereabouts- timeout is not exact)
     *     // but lets say that for some reason you want to execute in advance
     *     // of the interval expiring. You can invoke the execute method
     *    
     *     deferred.execute(); 
     *     
     *     // that would have invoked the onExecute call back if one had been
     *     // defined and set the hasExecuted, fault, result values and then
     *     // called the dispose method afterward
     *      
     *     // if you wanted to determine the time expired, this is how you
     *     // you would do it
     *     
     *     var now= new Date().getTime()
     *     ,   duration= now - deferred.createdOn
     *     ,   timeRemainingIfIHadntExecuted= deferred.interval - duration
     * 
     *     // alternatively, you may want to abort a deferred method. Assuming
     *     // you haven't already executed, you can just do this
     *     
     *     deferred.dispose(); 
     *     
     *     // that cancelled the deferred method from executing and removed
     *     // some internal references to faciliate garbage collection. The
     *     // onExecute call back was not invoked, and no other properties
     *     // were changed
     * 
     * </pre></code>
     * 
     * @param {Number} interval   The number of milliseconds to expire before 
     *                            executing this function
     * @param {Object} scope      Optional. An object scope in which to 
     *                            execute this function
     * @param {...Object} rest    Any number of arguments to curry the 
     *                            function with
     * @return {Object}           The deferred object detailed above.
     * @requires Function#bind
     * @see Function#bind
     * @memberOf Function
     * @addon
     */
    F.defer= function (interval, scope) 
    {
        var method= this.bind.apply(this, [scope].concat(S.call(arguments, 2)))
        ,   deferred= 
            {
                hasExecuted: false
            ,   createdOn: new Date().getTime()
            ,   interval: interval
            ,   result: null
            ,   fault: null
            ,   dispose: function () 
                {
                    clearTimeout(this.timeoutId);
                    delete this.timeoutId;
                    this.execute= function () {;};
                    method= null;
                }
            ,   execute: function () 
                {
                    var status= false;
                    deferred.hasExecuted= true;
                    try 
                    {
                        deferred.result= method();
                        status= true;
                    }
                    catch (thrown) 
                    {
                        deferred.fault= thrown;
                    }
                    deferred.dispose();
                    if ('function' === typeof deferred.onExecute)
                        deferred.onExecute(status);
                }
            };
        
        deferred.timeoutId= setTimeout(deferred.execute, interval);
        return deferred;
    };
};
